package org.nativejpa.transaction;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;
import javax.transaction.RollbackException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.Transaction;
import javax.transaction.Synchronization;
import javax.transaction.InvalidTransactionException;
import java.util.Properties;

/**
 * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
 * @create 2009-3-24 15:07:16
 */
public abstract class TransactionManagerFactory {

    protected TransactionManagerFactory() {
        init();
    }

    public abstract String getVendor();

    public abstract Properties getProperties();

    protected abstract void setDefaultTransactionTimeout(int defaultTransactionTimeout);

    protected abstract TransactionManager getVendorTransactionManager();

    public abstract void init();

    public abstract void shutdown();

    private ProxyTransactionManager tm;

    public synchronized TransactionManager getTransactionManager() {
        if(tm == null) {
            tm = new ProxyTransactionManager(getVendorTransactionManager());
        }
        return tm;
    }

    public synchronized  UserTransaction getUserTransaction() {
        if(tm == null) {
            tm = new ProxyTransactionManager(getVendorTransactionManager());
        }
        return tm;        
    }


    /**
     * register a Synchronization after begin a new Transaction
     */
    class ProxyTransactionManager implements TransactionManager, UserTransaction {
        final TransactionManager vendorTM;

        ProxyTransactionManager(final TransactionManager vendorTM) {
            this.vendorTM = vendorTM;
        }

        public void begin() throws NotSupportedException, SystemException {
                vendorTM.begin();
                final Transaction tx = vendorTM.getTransaction();
//                TransactionConnectionManager.setTransaction(tx);
                try {
                    // 注册事务同步器，在事务 commit/rollback 的时候， 释放数据库连接
                    tx.registerSynchronization(new Synchronization() {
                        public void beforeCompletion() {
                        }

                        public void afterCompletion(int i) {
                            // releaseTxConnection, 由 EntityManagerImpl.getConnection 时add
                            TransactionConnectionManager.releaseTxConnections(tx);
                        }
                    });
                }
                catch (RollbackException e) {
                    throw new SystemException("Caught RoolbackException: " + e.getMessage());
                }
            }

            public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException {
                vendorTM.commit();
            }

            public int getStatus() throws SystemException {
                return vendorTM.getStatus();
            }

            public Transaction getTransaction() throws SystemException {
                return vendorTM.getTransaction();
            }

            public void resume(Transaction transaction) throws InvalidTransactionException, IllegalStateException, SystemException {
                vendorTM.resume(transaction);
            }

            public void rollback() throws IllegalStateException, SecurityException, SystemException {
                vendorTM.rollback();
            }

            public void setRollbackOnly() throws IllegalStateException, SystemException {
                vendorTM.setRollbackOnly();
            }

            public void setTransactionTimeout(int i) throws SystemException {
                vendorTM.setTransactionTimeout(i);
            }

            public Transaction suspend() throws SystemException {
                return vendorTM.suspend();
            }
        }


}
